﻿using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Tsual.Util;
using Tsual.Util.Redis;
using Tsual.Wechat.Cache;
using Tsual.Wechat.Message;
using Tsual.Wechat.Message.Exceptions;
using Tsual.Wechat.Message.Impl;
using Tsual.Wechat.Message.Impl.Internal;
using Tsual.Wechat.Message.Impl.Response;
using Tsual.Wechat.Message.Interface.Request;
using Tsual.Wechat.Message.Interface.Response;
using System.Web;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Microsoft.AspNetCore.Mvc;
using System.Xml.Linq;
using System.Net;
using System.Collections;
using Tsual.Wechat;
using Tsual.Wechat.Formatters;
using Microsoft.AspNetCore.Hosting;
using Tsual.Wechat.Enums;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Tsual.Wechat.Filters;
using System.Reflection;
using Tsual.Wechat.Controllers;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.Extensions.Options;
using System.ComponentModel.DataAnnotations;
using Tsual.Wechat.Pipes;


namespace Microsoft.Extensions.DependencyInjection
{
    public static class WechatServiceConfigurationExtensions
    {
        public static IServiceCollection AddTsualWechat(this IServiceCollection services, Action<TsualWechatOption> setupAction)
        {
            if (services is null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            if (setupAction is null)
            {
                throw new ArgumentNullException(nameof(setupAction));
            }

            if (WechatContext._Instance.Configured)
                return services;

            services.AddHttpClient();
            services.AddOptions();
            services.Configure(setupAction);
            services.AddSingleton<IWechatContextProvider, DefaultWechatContextProvider>();
            services.BuildServiceProvider().GetService<IWechatContextProvider>();

            return services;
        }

        public static IMvcBuilder AddDefaultWechatController(this IMvcBuilder mvcBuilder)
        {
            mvcBuilder.Services.AddSingleton<WechatServerAddressFilter>();
            mvcBuilder.Services.PostConfigure<MvcOptions>(cfg =>
            {
                cfg.InputFormatters.Insert(0, new WechatMessageInputFormatter());
                cfg.OutputFormatters.Insert(0, new WechatMessageOutputFormatter());
            });
            mvcBuilder.ConfigureApplicationPartManager(apm => apm.FeatureProviders.Add(new WechatControllerProvider()));
            return mvcBuilder;
        }
    }


}


namespace Microsoft.Extensions.DependencyInjection
{
    public static class RedisCacheServiceCollectionExtensions
    {
        public static IRedisServiceOption AddSingleRedisCache(this IServiceCollection services, ConfigurationOptions redisOption)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            var obj = ConnectionMultiplexer.Connect(redisOption);
            services.AddSingleton(obj);
            services.AddTransient(p => p.GetService<ConnectionMultiplexer>().GetDatabase());

            return new RedisServiceOption() { ServiceCollection = services };
        }

        public static IRedisServiceOption AddRedLock(this IRedisServiceOption services)
        {
            services.ServiceCollection.AddSingleton(p => RedLockFactory.Create(new List<RedLockMultiplexer>() { p.GetService<ConnectionMultiplexer>() }));
            return services;
        }
    }

    public interface IRedisServiceOption
    {
        IServiceCollection ServiceCollection { get; set; }
    }

    public class RedisServiceOption : IRedisServiceOption
    {
        public IServiceCollection ServiceCollection { get; set; }
    }
}